#!/usr/bin/env python
"""
Acorn-SDR (A Collaboration of Radio Nodes)
(c) Bob Cowdery (G3UKB) 2009

File: app_main_gui.py
Date: January 2009

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

The author can be reached by email at

bob@g3ukb.co.uk

================================================================================
Module Description:

The main gui service.

"""

#-------------------------------------------------------------------------------
# System imports
import sys
import os
from time import sleep
import subprocess
import Ice, IceStorm

# Application imports
import gtk_mini_gui as gui
import ice_helpers
import utils

# Import the Ice interface definitions
import AcornLifeCycle
import AcornRxUpdate
import AcornRxControl
import AcornRxDsp
import AcornPersist

#===============================================================================
# Ice life-cycle events for the GUI
class LifeCycleI(AcornLifeCycle.LifeCycle):
    
    #---------------------------------------------------------------------------   
    def __init__(self, gui_impl, persist):
        self.gui_impl = gui_impl
        self.persist = persist
      
    #---------------------------------------------------------------------------
    def start(self, current=None):
        self.gui_impl.start()
     
    #---------------------------------------------------------------------------   
    def stop(self, current=None):
        self.gui_impl.stop()
    
    #---------------------------------------------------------------------------    
    def terminate(self, current=None):
        self.gui_impl.terminate()
        
#===============================================================================
# Ice update events for the GUI
class RxUpdateI(AcornRxUpdate.RxUpdate):
    
    #---------------------------------------------------------------------------   
    def __init__(self, gui_impl, persist, track):
        self.gui_impl = gui_impl
        self.persist = persist
        self.track = track
    
    #---------------------------------------------------------------------------   
    def trackUpdate(self, track, current=None):
        self.track = track
        self.gui_impl.thd_track_update(track)
        
    #---------------------------------------------------------------------------   
    def freqUpdate(self, freq, current=None):
        self.gui_impl.thd_freq_update(freq)
        
    #---------------------------------------------------------------------------  
    def oscUpdate(self, osc, current=None):
        self.gui_impl.thd_osc_update(osc)
    
    #---------------------------------------------------------------------------  
    def modeUpdate(self, mode, current=None):
        self.gui_impl.thd_mode_update(mode)
      
    #---------------------------------------------------------------------------  
    def filterUpdate(self, filter, current=None):
        self.gui_impl.thd_filter_update(filter)
      
    #---------------------------------------------------------------------------  
    def agcUpdate(self, mode, current=None):
        self.gui_impl.thd_agc_update(mode)
      
    #---------------------------------------------------------------------------  
    def gainUpdate(self, gain, current=None):
        self.gui_impl.thd_gain_update(gain)
     
    #---------------------------------------------------------------------------  
    def rxOnUpdate(self, rx, current=None):
        self.gui_impl.thd_rx_on_update(rx)
        
     #---------------------------------------------------------------------------  
    def rxOffUpdate(self, rx, current=None):
        self.gui_impl.thd_rx_off_update(rx)
        
    #---------------------------------------------------------------------------  
    def rxListenUpdate(self, rx, current=None):
        self.gui_impl.rx_listen_update(rx)
    
    #---------------------------------------------------------------------------  
    def rxPanUpdate(self, pan, current=None):
        self.gui_impl.thd_pan_update(pan)
        
    #---------------------------------------------------------------------------  
    def rxBinUpdate(self, state, current=None):
        self.gui_impl.thd_bin_update(state)
        
    #---------------------------------------------------------------------------  
    def rxNrUpdate(self, state, current=None):
        self.gui_impl.thd_nr_update(state)
        
    #---------------------------------------------------------------------------  
    def rxNbUpdate(self, state, current=None):
        self.gui_impl.thd_nb_update(state)
        
    #---------------------------------------------------------------------------  
    def rxAnfUpdate(self, state, current=None):
        self.gui_impl.thd_anf_update(state)

#===============================================================================
# Ice config events for the GUI
class RxConfigI(AcornRxUpdate.RxConfig):
    
    #---------------------------------------------------------------------------   
    def __init__(self, gui_impl, persist):
        self.gui_impl = gui_impl
        self.persist = persist
      
    #---------------------------------------------------------------------------   
    def configUpdate(self, name, current=None):
        # Update the gtk_options as there may be more than one options GUI running
        self.gui_impl.update_option(name)
        
#===============================================================================
# The main class of 'a' GUI application
class AppMainGui(Ice.Application):
  
    #---------------------------------------------------------------------------
    def __init__(self):
        pass
            
    #---------------------------------------------------------------------------
    # Run the app
    def run(self, args):
       
        #-----------------------------------------------------------------------
        # persist interface
        persist = ice_helpers.get_interface('GUI', self.communicator, AcornPersist.PersistPrx, 'Persist.Proxy')
        
        # Get the radio state, everything else should be running
        running = utils.persist_get(persist, 'Dynamic', 'running')
        
        # The a and b data for the default radio
        # The offsets are still valid for a VR
        track = utils.persist_get(persist, 'Dynamic', 'track')
        vfoa = utils.persist_get(persist, 'Dynamic', 'vfoa')
        offseta = utils.persist_get(persist, 'Dynamic', 'offseta')
        modea = utils.persist_get(persist, 'Dynamic', 'modea')
        filtera = utils.persist_get(persist, 'Dynamic', 'filtera')
        vfob = utils.persist_get(persist, 'Dynamic', 'vfob')
        offsetb = utils.persist_get(persist, 'Dynamic', 'offsetb')
        modeb = utils.persist_get(persist, 'Dynamic', 'modeb')
        filterb = utils.persist_get(persist, 'Dynamic', 'filterb')
        
        # Single mode/filter pair for each VR
        mode = utils.persist_get(persist, 'Dynamic', 'mode')
        filter = utils.persist_get(persist, 'Dynamic', 'filter')
        
        # These are common across default and VR's
        pan = utils.persist_get(persist, 'Dynamic', 'pan')
        agc_mode = utils.persist_get(persist, 'Dynamic', 'agcmode')
        af_gain = utils.persist_get(persist, 'Dynamic', 'gain')
        bin = utils.persist_get(persist, 'Dynamic', 'bin')
        nr = utils.persist_get(persist, 'Dynamic', 'nr')
        nb = utils.persist_get(persist, 'Dynamic', 'nb')
        anf = utils.persist_get(persist, 'Dynamic', 'anf')
        
        # Data for radios 1-3
        listen = None
        cap_multirx = utils.persist_get(persist, 'Capability', 'multirx')
        if cap_multirx:
            listen = utils.persist_get(persist, 'Dynamic', 'listen')
            running_1 = utils.persist_get(persist, 'Dynamic', 'running', 1)
            offseta_1 = utils.persist_get(persist, 'Dynamic', 'offseta', 1)
            offsetb_1 = utils.persist_get(persist, 'Dynamic', 'offsetb', 1)
            mode_1 = utils.persist_get(persist, 'Dynamic', 'mode', 1)
            filter_1 = utils.persist_get(persist, 'Dynamic', 'filter', 1)
            pan_1 = utils.persist_get(persist, 'Dynamic', 'pan', 1)
            running_2 = utils.persist_get(persist, 'Dynamic', 'running', 2)
            offseta_2 = utils.persist_get(persist, 'Dynamic', 'offseta', 2)
            offsetb_2 = utils.persist_get(persist, 'Dynamic', 'offsetb', 2)
            mode_2 = utils.persist_get(persist, 'Dynamic', 'mode', 2)
            filter_2 = utils.persist_get(persist, 'Dynamic', 'filter', 2)
            pan_2 = utils.persist_get(persist, 'Dynamic', 'pan', 2)
            running_3 = utils.persist_get(persist, 'Dynamic', 'running', 3)
            offseta_3 = utils.persist_get(persist, 'Dynamic', 'offseta', 3)
            offsetb_3 = utils.persist_get(persist, 'Dynamic', 'offsetb', 3)
            mode_3 = utils.persist_get(persist, 'Dynamic', 'mode', 3)
            filter_3 = utils.persist_get(persist, 'Dynamic', 'filter', 3)
            pan_3 = utils.persist_get(persist, 'Dynamic', 'pan', 3)
            
        # Paths
        glade_path = utils.persist_get(persist, 'Profile', 'path.glade')
        HOME = os.environ['ACORN_HOME']
        console_path = HOME + utils.persist_get(persist, 'Profile', 'path.DEFAULT_GUI')
        display_path = HOME + utils.persist_get(persist, 'Profile', 'path.DEFAULT_DISPLAY')
        ice_config = utils.persist_get(persist, 'Profile', 'path.iceconfig')
        
        # Window attributes
        w_pos = (utils.persist_get(persist, 'Profile', 'window.x'),
                 utils.persist_get(persist, 'Profile', 'window.y'),
                 utils.persist_get(persist, 'Profile', 'window.width'),
                 utils.persist_get(persist, 'Profile', 'window.height'))
        
        #-----------------------------------------------------------------------
        # Event names used here
        publish_to_lc = 'life_cycle_events'
        publish_to_rx_control = 'rx_control_events'
        publish_to_rx_dsp = 'rx_dsp_events'
        publish_to_rx_updates = 'rx_update_events'
        subscribe_to_rx_updates = 'rx_update_events'
        subscribe_to_rx_config = 'rx_config_events'
        subscribe_to_lc = 'life_cycle_events'
  
        #-----------------------------------------------------------------------
        # This is the same for both publishers and subscribers
        # Get the IceStorm topic manager interface
        manager = ice_helpers.get_topic_manager('GUI', self.communicator)
    
        # Retrieve the subscriber topic
        rx_update_topic = ice_helpers.get_topic('GUI', manager, subscribe_to_rx_updates)
        life_cycle_topic = ice_helpers.get_topic('GUI', manager, subscribe_to_lc)
        rx_config_topic = ice_helpers.get_topic('GUI', manager, subscribe_to_rx_config)
              
        # Retrieve the publisher topics
        publish_topic_life_cycle = ice_helpers.get_topic('GUI', manager, publish_to_lc)
        publish_topic_rx_control = ice_helpers.get_topic('GUI', manager, publish_to_rx_control)
        publish_topic_rx_dsp = ice_helpers.get_topic('GUI', manager, publish_to_rx_dsp)
        publish_topic_rx_update = ice_helpers.get_topic('GUI', manager, publish_to_rx_updates)
              
        #-----------------------------------------------------------------------
        # Publisher side
        # Get the topic's publisher object, and create a hw proxy with
        # the mode specified as an argument of this application.
        #
        publisher_life_cycle = publish_topic_life_cycle.getPublisher();
        publisher_life_cycle = publisher_life_cycle.ice_oneway();        
        life_cycle_publisher = AcornLifeCycle.LifeCyclePrx.uncheckedCast(publisher_life_cycle)
        
        publisher_rx_control = publish_topic_rx_control.getPublisher();
        publisher_rx_control = publisher_rx_control.ice_oneway();        
        rx_control_publisher = AcornRxControl.RxControlPrx.uncheckedCast(publisher_rx_control)
        
        publisher_rx_dsp = publish_topic_rx_dsp.getPublisher();
        publisher_rx_dsp = publisher_rx_dsp.ice_oneway();        
        rx_dsp_publisher = AcornRxDsp.RxDspPrx.uncheckedCast(publisher_rx_dsp)       
        
        publisher_rx_update = publish_topic_rx_update.getPublisher();
        publisher_rx_update = publisher_rx_update.ice_oneway();        
        rx_update_publisher = AcornRxUpdate.RxUpdatePrx.uncheckedCast(publisher_rx_update)
        
        #-----------------------------------------------------------------------
        # Initialise the GUI as its needed for the adapter and requires the publishers
        # Set up the initial config
        init = {'listen': listen}
        init[0] = {'vfoa':vfoa,'vfob':vfob,'offseta':offseta,'offsetb':offsetb,'modea':modea,'modeb':modeb,'filtera':filtera,'filterb':filterb,'bin':bin,'nr':nr,'nb':nb,'anf':anf,'af_gain':af_gain,'agc_mode':agc_mode,'track':track}
        if cap_multirx:
            init[1] = {'running':running_1,'offseta':offseta_1,'offsetb':offsetb_1,'mode':mode_1,'filter':filter_1, 'pan':pan_1}
            init[2] = {'running':running_2,'offseta':offseta_2,'offsetb':offsetb_2,'mode':mode_2,'filter':filter_2, 'pan':pan_2}
            init[3] = {'running':running_3,'offseta':offseta_3,'offsetb':offsetb_3,'mode':mode_3,'filter':filter_3, 'pan':pan_3}
        gui_impl = gui.AppGui(w_pos, glade_path, persist, running, life_cycle_publisher, rx_control_publisher, rx_dsp_publisher, rx_update_publisher, console_path, display_path, ice_config, init)
        
        #-----------------------------------------------------------------------
        # Subscriber side
        # Create an adapter for the subscribers   
        adapter_1 = self.communicator().createObjectAdapter("RxUpdate.Subscriber")
        subId_1 = Ice.Identity()
        subId_1.name = Ice.generateUUID()        
        # Add the update interface
        subscriber_1 = adapter_1.add(RxUpdateI(gui_impl, persist, track), subId_1)
        # Subscribe to the topic - set up proxy
        ice_helpers.subscribe('GUI', rx_update_topic, subscriber_1, id)
        # Now we can receive callbacks   
        adapter_1.activate()
        
        adapter_2 = self.communicator().createObjectAdapter("LifeCycle.Subscriber")
        subId_2 = Ice.Identity()
        subId_2.name = Ice.generateUUID()        
        # Add the update interface
        subscriber_2 = adapter_2.add(LifeCycleI(gui_impl, persist), subId_2)
        # Subscribe to the topic - set up proxy
        ice_helpers.subscribe('GUI', life_cycle_topic, subscriber_2, id)
        # Now we can receive callbacks   
        adapter_2.activate()
        
        adapter_3 = self.communicator().createObjectAdapter("RxConfig.Subscriber")
        subId_3 = Ice.Identity()
        subId_3.name = Ice.generateUUID()        
        # Add the update interface
        subscriber_3 = adapter_3.add(RxConfigI(gui_impl, persist), subId_3)
        # Subscribe to the topic - set up proxy
        ice_helpers.subscribe('GUI', rx_config_topic, subscriber_3, id)
        # Now we can receive callbacks   
        adapter_3.activate()
                 
        #-----------------------------------------------------------------------
        # Update all listeners state by sending events into the system
        if track <> None:
            if (track == 'vfoa') or (track == 'offseta'):
                if vfoa <> 'Empty': rx_control_publisher.freqSet(vfoa)
                if offseta <> 'Empty': rx_dsp_publisher.oscSet(offseta)
                if modea <> 'Empty': rx_dsp_publisher.setMode(modea)
                if filtera <> 'Empty': rx_dsp_publisher.setFilter(filtera)
            else:
                if vfob <> 'Empty': rx_control_publisher.freqSet(vfob)
                if offsetb <> 'Empty': rx_dsp_publisher.oscSet(offsetb)
                if modeb <> 'Empty': rx_dsp_publisher.setMode(modeb)
                if filterb <> 'Empty': rx_dsp_publisher.setFilter(filterb)
        if pan <> 'Empty': rx_dsp_publisher.setRxPan(pan)
        if agc_mode <> 'Empty': rx_dsp_publisher.setAgc(agc_mode)
        if af_gain <> 'Empty': rx_dsp_publisher.setGain(af_gain)
        if bin <> 'Empty': rx_dsp_publisher.setBin(bin)
        if nr <> 'Empty': rx_dsp_publisher.setNr(nr)
        if nb <> 'Empty': rx_dsp_publisher.setNb(nb)
        if anf <> 'Empty': rx_dsp_publisher.setAnf(anf)
        
        if track: rx_update_publisher.trackUpdate(track)
        
        #-----------------------------------------------------------------------
        print 'Acorn-SDR (GUI) running..'
        # Start the GUI
        quit = gui_impl.main()
        # This only returns when the GUI is closed
        
        # Unsubscribe all subscribed objects.
        # causes issues at the moment
        #rx_update_topic.unsubscribe(subscriber_1)
        #rx_life_cycle_topic.unsubscribe(subscriber_2)
        #rx_config_topic.unsubscribe(subscriber_3)
        
        # Don't close services unless we are quiting
        #if quit:
            # Terminate all other applications
        #    start_jack = utils.persist_get(persist, 'Profile', 'jack.load')
        #    if start_jack:
        #        subprocess.Popen(['killall', 'jackd'])
        #    subprocess.Popen(['killall', 'icebox'])
        
#===============================================================================
#===============================================================================
# Start from the command line
if __name__ == "__main__":
   
  app = AppMainGui()
  app.main(sys.argv, sys.argv[1])
  
  # Announce we are going 
  print 'Acorn-SDR (GUI) closing..'
  